package wiki.liven.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import wiki.liven.Exception.RepeatkillException;
import wiki.liven.Exception.SeckillClosedException;
import wiki.liven.Exception.SeckillException;
import wiki.liven.dao.SeckillDao;
import wiki.liven.dao.SuccessSeckilledDao;
import wiki.liven.dto.Exposer;
import wiki.liven.dto.SecKillExcution;
import wiki.liven.euum.SeckillEunm;
import wiki.liven.pojo.Seckill;
import wiki.liven.pojo.SuccessSeckilled;
import wiki.liven.service.SeckillService;

import java.util.Date;
import java.util.List;

/**
 * Created by leven on 2016/10/16.
 */
@Service
public class SeckillServiceImpl implements SeckillService {


    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    /*
        为什么会有报错呢?
     */
    @Autowired
    private SeckillDao seckillDao;
    @Autowired
    private SuccessSeckilledDao successDao;

    private final String slat = "qwerty23asdfa~~!@!#$%fsldaifjio";

    /**
     * 查询所有秒杀产品
     *
     * @return 秒杀产品列表
     */
    @Override
    public List<Seckill> findAll() {
        List<Seckill> seckills = seckillDao.findAll();
        return seckills;
    }

    /**
     * 查询单个秒杀产品
     *
     * @param secKillId 秒杀产品ID
     * @return 单个秒杀产品实体
     */
    @Override
    public Seckill findOne(Long secKillId) {
        Seckill seckill = seckillDao.findById(secKillId);
        return seckill;
    }

    /**
     * 当秒杀活动开始的时候，输出秒杀地址；
     * 当秒杀活动没有开始时，返回倒计时和秒杀开启时间
     *
     * @param seckillId
     * @return 输出秒杀URLDTO
     */
    @Override
    public Exposer exportSecKillUrl(Long seckillId) {
        Date nowOnServer = new Date();
        Seckill seckill = seckillDao.findById(seckillId);
        if (null == seckill) {
            return new Exposer(false, seckillId);
        }
        Date strtTime = seckill.getStartTime();
        Date endTime = seckill.getEndTime();
        if (nowOnServer.before(strtTime) || nowOnServer.after(endTime)) {
            return new Exposer(false, seckillId, nowOnServer.getTime(), strtTime.getTime(), endTime.getTime());
        }
        //输出秒杀地址
        String md5 = getMd5(seckillId);
        return new Exposer(true, seckillId, md5);
    }


    private String getMd5(long sexkillId) {
        String base = sexkillId + "/" + slat;
        String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
        return md5;
    }

    /**
     * 执行秒杀业务
     *
     * @param secKillId
     * @param userPhone
     * @param md5
     * @return
     * @throws RepeatkillException    重复秒杀异常
     * @throws SeckillClosedException 秒杀活动关闭异常
     */
    @Override
    @Transactional
    public SecKillExcution executeSecKill(Long secKillId, String userPhone, String md5) throws RepeatkillException, SeckillClosedException {
        /*
         *1.判断MD5的一致性
         * 2.减库存
         * 3.记录购买明细
         */
        if (null == md5 || !md5.equals(getMd5(secKillId))) {
            throw new SeckillException("秒杀地址已经被重写！");
        }
        Date timeOnServer = new Date();
        try {
            int result = seckillDao.updataNumber(secKillId, timeOnServer);
            if (result <= 0) {
                //数据表中没有记录被更新，一般是由于秒杀活动已经结束。
                throw new SeckillClosedException("秒杀活动已经关闭！");
            } else {
                int successSeckillState = successDao.insterTheSuccessSeckilled(secKillId, userPhone);
                if (successSeckillState <= 0) {
                    //该用户重复下单
                    throw new RepeatkillException("该用户重复下单！");
                } else {
                    SuccessSeckilled seckilled = successDao.findSuccessSeckilled(secKillId, userPhone);
                    return new SecKillExcution(secKillId, SeckillEunm.SUCCESS, seckilled);
                }
            }
        } catch (SeckillClosedException close) {
            throw close;
        } catch (RepeatkillException repeat) {
            throw repeat;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SeckillException("秒杀内部异常:" + e.getMessage());
        }
    }
}
